#pragma once

#include "BasicTypes.h"

namespace MOE
{
    namespace Core
    {
		class ClassMeta;

        // Wraps around any meta-enabled types.
		// Types differs from ClassMetas in that multiple Types can refer to the same ClassMeta.
		// For example, both "int" and "int*" use the ClassMeta of int, but are different types.
        class Type
        {
		public:
			// Defines a default instance.
			static const Type kDefault;

        public:
			// Default constructor for Type.
			// This constructs a Nil type.
			Type();

			// Constructor for Type.
			// Parameters:
			// - baseClassMeta: Pointer to the base ClassMeta used by this type.
			// - refType: Enum to determine whether this is a value or a reference. In an array, this applies to each element of the array.
			// - arrType: Enum to determine whether this is a single value or an array.
			// - numElements: Number of elements in the array. Only used by ArrayType::kEmbeddedArray, otherwise this value is ignored and GetNumElements will always return 1.
			explicit Type(const ClassMeta& baseClassMeta, ReferenceType refType = ReferenceType::kValue, ArrayType arrType = ArrayType::kSingle, tSize numElements = 0);

			// Get the class meta.
			const ClassMeta& GetClassMeta() const { return mBaseClassMeta; }

			// Get the reference type.
			ReferenceType GetReferenceType() const { return mReferenceType; }

			// Get the array type.
			ArrayType GetArrayType() const { return mArrayType; }

			// Get the number of elements in the array. If this is not an array type, this returns 1.
			tSize GetNumElements() const { return mNumElements; }

			// Get the size of this type.
			tSize GetTypeSize() const { return mTypeSize; }

			// Copy the value contained in this type from source to destination.
			// Reference types only copy the reference (shallow copy).
			void CopyValue(tUntypedConstRef source, tUntypedRef destination) const;

		private:
			const ClassMeta& mBaseClassMeta;
			ReferenceType mReferenceType;
			ArrayType mArrayType;
			tSize mNumElements;
			tSize mTypeSize;
        };
    }
}
